package org.jetlinks.community.device.service;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
import org.hswebframework.reactor.excel.ReactorExcel;
import org.hswebframework.web.api.crud.entity.PagerResult;
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
import org.hswebframework.web.bean.FastBeanCopier;
import org.hswebframework.web.crud.service.GenericReactiveCrudService;
import org.jetlinks.community.device.entity.DemoEntity;
import org.jetlinks.community.device.response.DemoInfo;
import org.jetlinks.community.device.web.excel.DemoExportInfo;
import org.jetlinks.community.io.excel.ImportExportService;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service
@AllArgsConstructor
@Slf4j
public class DemoService extends GenericReactiveCrudService<DemoEntity,String> {

    private ReactiveRepository<DemoEntity, String> reactiveRepository;


    private final DataBufferFactory bufferFactory = new DefaultDataBufferFactory();

    private ImportExportService importExportService;

    public Mono<PagerResult<DemoInfo>> demoQueryPager(QueryParamEntity queryParam){
        return this
            .queryPager(queryParam)
            .flatMap(result-> Flux
                .fromIterable(result.getData())
                .collectList()
                .map(demo -> PagerResult.of(result.getTotal(), demo, queryParam)))
            .map(page -> convertPage(page, DemoInfo::of));
    }

    public Mono<Void> demoSave(DemoEntity demo) {
        return this
            .save(demo)
            .then();
    }

    public Mono<Integer> demoUpdate(DemoEntity demo) {
        return this
            .updateById(demo.getId(),demo);
    }

    public Mono<Integer> demoRemove(Mono<List<String>> idList) {
        return idList
            .flatMapMany(Flux::fromIterable)
            .as(this::deleteById);
    }

//    导入mvc
//    public Mono<Void> doImport(MultipartFile file) throws IOException {
//        return importExportService
//            .doImport(DemoExportInfo.class,file.getInputStream())
//            .collectList()
//            .map(info->{
//                List<DemoEntity> lists=new ArrayList<>();
//                info.forEach(demoExportInfoRowResult -> {
//                    lists.add(demoExportInfoRowResult.getResult().toDemoInfo());
//                });
//                return lists;
//            })
//            .flatMapMany(Flux::fromIterable)
//            .as(reactiveRepository::save)
//            .then();
//    }

    public Mono<Void> doImport(Mono<FilePart> filePart) throws IOException {
        return filePart.flatMapMany(file->file.content())
            .map(dataBuffer ->dataBuffer.asInputStream())
            .reduce(SequenceInputStream::new)
            .flatMap(inputStream -> {
                return importExportService
                    .doImport(DemoExportInfo.class,inputStream)
                    .collectList()
                    .map(info->{
                        List<DemoEntity> lists=new ArrayList<>();
                        info.forEach(demoExportInfoRowResult -> {
                            lists.add(demoExportInfoRowResult.getResult().toDemoInfo());
                        });
                        return lists;
                    })
                    .flatMapMany(Flux::fromIterable)
                    .as(reactiveRepository::save)
                    .then();
            });
    }

    /**
     * 导出
     */
    public Mono<Void> export(ServerHttpResponse response, QueryParamEntity parameter, String format) throws IOException {
        return ReactorExcel.<DemoExportInfo>writer(format)
            .headers(DemoExportInfo.getExportHeaderMapping(Collections.emptyList(), Collections.emptyList()))
            .writeBuffer(
                this
                    .query(parameter)
                    .map(entity -> {
                        DemoExportInfo exportEntity = FastBeanCopier.copy(entity, new DemoExportInfo(), "state");
                        return exportEntity;
                    })
                , 512 * 1024)//缓冲512k
            .doOnError(err -> log.error(err.getMessage(), err))
            .map(bufferFactory::wrap)
            .as(response::writeWith);
    }

    private <R, T> PagerResult<R> convertPage(PagerResult<T> source, Function<T, R> mapper) {
        @SuppressWarnings("all")
        PagerResult<R> newResult = FastBeanCopier.copy(source, source.getClass());

        newResult.setData(
            source.getData()
                .stream()
                .map(mapper)
                .collect(Collectors.toList())
        );
        return newResult;
    }

}
